'''
    Goblinoid: Experience all of MediaGoblin on an Android Device
    Copyright (C) 2015 Dylan Jeffers

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

# models for app root
from __future__ import print_function
from os.path import join

from kivy.app import App
from kivy.properties import ObjectProperty, DictProperty, ListProperty,\
    NumericProperty, BooleanProperty
from kivy.uix.widget import Widget
from kivy.metrics import sp

from pypump import JSONStore
# from pypump.models.media import Image
from pypump.models.image import Image

# TODO come up with a better name than feedsections + modularize it more
import goblinoid.config.feedsections as fs
from thread_queue import ThreadQueue
import threading


# store for user's credentials
class UserStore(JSONStore):
    @classmethod
    def get_filename(cls):
        return join(App.get_running_app().user_data_dir,
                    'MediaGoblin/credentials.json')


class PumpService(Widget):
    pump = ObjectProperty(None)
    inbox = ListProperty([])
    comment_modals = ListProperty([])
    refresh_inbox = ListProperty([])
    screen_dict = DictProperty()
    feed_data = ListProperty()
    refresh_data = ListProperty()
    feed_index = NumericProperty(0)
    batch_size = NumericProperty(20)
    already_prefetching = BooleanProperty(False)
    already_refreshing = BooleanProperty(False)
    prefetch_thread = ObjectProperty()
    refresh_thread = ObjectProperty()
    refresh_callback = ObjectProperty()
    prefetch_callback = ObjectProperty()

    build_activity_dict = fs.mg_activity_dict

    def __init__(self, activity_dict_style=fs.mg_activity_dict):
        super(PumpService, self).__init__()
        self.prefetch_queue = ThreadQueue(self.update_feed)
        self.refresh_queue = ThreadQueue(self.refresh_feed)
        self.feed_data_generator = fs.mg_activity_dict
        self.build_activity_dict = activity_dict_style
        self.init_screen_dict()
        self.data_dir = join(App.get_running_app().user_data_dir,
                             'MediaGoblin')
        self.init_screen_dict()

    @classmethod
    def pumpity(cls):
        return cls(fs.pumpity_activity_dict)

    def get_data_dir(self):
        return self.data_dir

    def init_screen_dict(self):
        # Note, the following imports depend on UserStore class
        # above, so importing them here for now
        from goblinoid.login import loginview
        from goblinoid.profile import profileview
        from goblinoid.settings import settings
        from goblinoid.feed import feedview
        from goblinoid.media import mediaviews
        from goblinoid.root import actionview
        self.screen_dict = dict([
            ('login', loginview.Login),
            ('webfinger', loginview.WebFinger),
            ('verify', loginview.Verify),
            ('action', actionview.ActionLayout),
            ('settings', settings.Settings),
            ('feed', feedview.FeedView),
            ('upload', mediaviews.UploadView),
            ('profile', profileview.ProfileView)
            ])

    def on_screen_dict(self, instance, value):
        print ('updated screen dict')

    def on_pump(self, instance, pump):
        pass

    def start_prefetch(self, callback):
        if not self.already_prefetching and not self.already_refreshing:
            print ('updating feed')
            self.already_prefetching = True
            self.prefetch_callback = callback
            self.prefetch_thread = PumpThread(self.prefetch_queue, self.pump, self.feed_index, self.batch_size)
            self.prefetch_thread.start()
            self.feed_index += self.batch_size

    def start_refresh(self, callback):
        if self.already_refreshing:
            return False
        if self.already_prefetching:
            self.prefetch_thread.is_running = False
            # note we may want to clear out the prefetch_queue at this point
            self.already_prefetching = False
        print ('refreshing feed')
        self.already_refreshing = True
        self.refresh_callback = callback
        self.feed_index = 0
        self.refresh_thread = PumpThread(self.refresh_queue, self.pump, self.feed_index, self.batch_size)
        self.refresh_thread.start()
        self.feed_index += self.batch_size
        return True

    def build_activity_content(self, activity, index):
        return self.build_activity_dict(activity, index)

    def update_feed(self):
        while True:
            try:
                index, activity = self.prefetch_queue.get()
                if index == 'none':
                    self.already_prefetching = False
                    self.start_prefetch()
                elif index == 'done':
                    self.prefetch_callback(self.feed_data)
                    self.feed_data = []
                    self.already_prefetching = False
                elif index == 'error':
                    App.get_running_app().dispatch_event('on_no_service')
                    self.prefetch_callback(self.feed_data)
                    self.feed_data = []
                    self.already_prefetching = False
                else:
                    print ('got new item')
                    inbox_index = len(self.inbox)
                    self.inbox.append(activity)
                    self.comment_modals.append(None)
                    activity_data = self.feed_data_generator(
                        activity, inbox_index)
                    self.feed_data.extend(activity_data)
            except:
                break

    def refresh_feed(self):
        while True:
            try:
                index, activity = self.refresh_queue.get()
                if index == 'none':
                    self.already_refreshing = False
                    self.start_refresh()
                elif index == 'done':
                    self.inbox = []
                    self.comment_modals = []
                    self.inbox = self.refresh_inbox
                    self.comment_modals = [None for i in range(0, len(self.inbox))]
                    self.refresh_callback(self.refresh_data)
                    self.refresh_data = []
                    self.refresh_inbox = []
                    self.already_refreshing = False
                elif index == 'error':
                    App.get_running_app().dispatch_event('on_no_service')
                    self.refresh_callback(self.refresh_data)
                    self.refresh_data = []
                    self.refresh_inbox = []
                    self.already_refreshing = False
                else:
                    self.refresh_inbox.append(activity)
                    activity_data = self.feed_data_generator(
                        activity, int(index))
                    self.refresh_data.extend(activity_data)
                    print (activity_data)
            except:
                break


class PumpThread(threading.Thread):

    def __init__(self, queue, pump, starting_index, batch_size, **kwargs):
        threading.Thread.__init__(self)
        self.queue = queue
        self.pump = pump
        self.index = starting_index
        self.batch_size = batch_size

    def run(self):
        self.fetch_feed_content()

    # NOTE: some mediagoblin instances cant do [non-zero-num:num]
    def fetch_feed_content(self):
        inbox_empty = True
        current_index = self.index
        print ('current index and batch size: {0}, {1}'.format(
                self.index, self.batch_size))
        try:
            for activity in self.pump.me.inbox.major[self.index:(self.index + self.batch_size)]:
                inbox_empty = False
                if isinstance(activity.obj, Image):
                    self.queue.put(str(current_index), activity)
                    current_index += 1
                    # activity_content = (self.feed_data_generator(
                    #     activity, current_index))
                    # if activity_content is not None:
                    #     self.queue.put(str(current_index), activity_content)
                    #     current_index += 1
            # implies we didn't get any hits:
            if current_index == self.index and inbox_empty is False:
                self.queue.put('none', None)
            elif inbox_empty is True:
                self.queue.put('error', None)
            else:
                self.queue.put('done', None)
        except:
            print ('got and error, no connection...')
            self.queue.put('error', None)
        self.is_running = False
